import pandas as pd
import numpy as np
import datetime

def _safe_get(d, key, default):
    return d[key] if key in d and d[key] is not None else default


def calculate_rest_car_count(collection_vehicle, car_list):
    """
    统计特定车辆类型（SCANIA、奔驰、解放、厢车）的休息数量
    :param car_list: 休息车辆车牌号列表
    :return: 每类车的休息数量统计
    """
    try:
        # 定义需要统计的车辆类型
        target_types = ["SCANIA", "奔驰", "解放", "厢车"]

        pipeline = [
            {
                '$match': {
                    'plate_number': {'$in': car_list},
                    'type': {'$in': target_types}  # 只统计特定类型
                }
            },
            {
                '$group': {
                    '_id': '$type',
                    'rest_count': {'$sum': 1}
                }
            }
        ]

        # 执行聚合查询
        result = list(collection_vehicle.aggregate(pipeline))

        # 创建结果字典，初始化所有类型数量为0
        result_dict = {car_type: 0 for car_type in target_types}

        # 更新有休息车辆的类型数量
        for item in result:
            if item['_id'] in result_dict:  # 这里使用_id字段
                result_dict[item['_id']] = item['rest_count']

        # 转换为列表格式，保持原始顺序
        final_result = [{'type': car_type, 'rest_count': result_dict[car_type]} for car_type in target_types]
        return final_result

    except Exception as e:
        print(f"统计过程中发生错误: {e}")
        # 返回所有类型数量为0的结果
        return [{'type': car_type, 'rest_count': 0} for car_type in target_types]


def time_to_minutes(time_series):
    """将时间字符串或Series转换为分钟数"""
    if isinstance(time_series, pd.Series):
        # 处理Series的情况
        return time_series.apply(lambda x: 0 if x == "-" or pd.isna(x) else
                                (int(x.hour) * 60 + int(x.minute) if isinstance(x, datetime.time) else
                                int(x.split(':')[0]) * 60 + int(x.split(':')[1])))
    else:
        # 处理单个值的情况
        if time_series == "-" or pd.isna(time_series) or not time_series:
            return 0
        elif isinstance(time_series, datetime.time):
            # 处理datetime.time对象
            return time_series.hour * 60 + time_series.minute
        else:
            # 处理字符串
            hours, minutes = map(int, time_series.split(':'))
            return hours * 60 + minutes

def minutes_to_time(minutes):
    if minutes == -1:
        return ""
    h = minutes // 60
    m = minutes % 60
    return f"{h}:{m:02d}"


def calculate_load_time(departure_time_str,type):
    if departure_time_str == "-" or not departure_time_str:
        return "-"
    if type == "废铝/铝卷":
        if departure_time_str == '7:00':
            return '晚上装车'
        else:
            t = time_to_minutes(departure_time_str)
            return minutes_to_time(t - 60)
    if type == '铝卷':
        t = time_to_minutes(departure_time_str)
        if 360 <= t < 540:
            return minutes_to_time(t - 30)
        elif 540 <= t:
            return minutes_to_time(t - 60)
    return "-"


def calculate_start_time(load_time_str,cargo_type):

    if load_time_str == "-" or not load_time_str:
        return "-"
    t = time_to_minutes(load_time_str)
    if cargo_type == '单顶':
        return minutes_to_time(t + 180)
    elif cargo_type == '铝棒':
        return minutes_to_time(t + 60)
    else:
        return load_time_str

def parse_shift(time_str):
    """解析时间字符串为班次"""
    if not time_str or time_str == 'None' or time_str == 'nan':
        return None
    try:
        # 提取小时数
        if ':' in time_str:
            hour = int(time_str.split(':')[0])
        else:
            hour = int(time_str)

        # 根据小时判断班次
        if hour < 9:
            return '早班'
        elif hour >= 17:
            return '晚班'
        else:
            return '中班'
    except:
        return None

def safe_parse_list(x):
    """安全处理输入数据，返回清理后的列表"""
    try:
        # 如果已经是列表，直接返回（过滤掉None值）
        if isinstance(x, list):
            # 过滤掉None和NaN值，并确保都是字符串
            result = []
            for item in x:
                if item is not None and not pd.isna(item):
                    result.append(str(item))
            return result

        # 处理其他情况（但根据您的数据，可能不会走到这里）
        if x is None or pd.isna(x):
            return []

        # 如果是字符串，尝试解析（备用方案）
        if isinstance(x, str):
            # 简单的字符串解析逻辑...
            pass

        return []
    except Exception as e:
        print(f"Error in safe_parse_list: {e}")
        return []



def get_allowed_shifts(history_shifts):
    if not history_shifts:
        return ['早班', '中班', '晚班']

    last_three = history_shifts[-3:] if len(history_shifts) >= 3 else []
    if len(last_three) == 3 and last_three[0] == last_three[1] and last_three[1] == last_three[2]:
        if last_three[0] == '早班':
            return ['中班', '晚班']
        elif last_three[0] == '晚班':
            return ['早班', '中班']
    return ['早班', '中班', '晚班']


def check_ab_vehicles(ab_drivers, driver_name):
    """
    检查车辆AB角优先级
    ab_drivers: 车辆的AB角司机列表
    driver_name: 当前选中的司机名称
    """

    if not ab_drivers or not isinstance(ab_drivers, list):
        return 0

    if driver_name in ab_drivers[0]:
        # 如果是AB角司机，返回高优先级
        return 2
    elif driver_name in ab_drivers[1]:
        # 如果是AB角司机，返回高优先级
        return 1
    else:
        # 如果不是AB角司机，返回普通优先级
        return 0



def plan_to_result(time_plan_df):
    # 定义列的顺序
    columns_order = [
        '司机姓名', '车牌号','发车时间', '装货时间', '货物类型', '司机所属地区', '是否接车','收车时间'
    ]
    time_plan_df = time_plan_df[columns_order]
    result_df1 = time_plan_df[ (time_plan_df['货物类型'] != '双零箔') &
                          (time_plan_df['货物类型'] != '废铝/铝卷') ]
    result_df1 = result_df1[(time_to_minutes(result_df1['装货时间']) < 721)]
    result_df1 = result_df1.sort_values('发车时间', key=lambda x: x.apply(time_to_minutes)).reset_index(drop=True)
    result_df1['始发地'] = '创元'
    result_df1['目的地'] = '晟通'
    result_df1.insert(0, '序', [f'第{i+1}车' for i in range(len(result_df1))])
    result_df1.loc[len(result_df1)] = [' '] * len(result_df1.columns)

    result_df2 = time_plan_df[time_plan_df['货物类型'] == '废铝/铝卷'].reset_index(drop=True)
    result_df2['目的地'] = np.where(result_df2['司机所属地区'] == '长沙','创元','晟通')
    result_df2['始发地'] = np.where(result_df2['司机所属地区'] == '常德','创元','晟通')
    result_df2.insert(0, '序', [f'第{i+len(result_df1)}车' for i in range(len(result_df2))])

    result_df3 = time_plan_df[(time_plan_df['装货时间'] != '晚上装车') & (time_plan_df['货物类型'] != '双零箔')]
    result_df3 = result_df3[(time_to_minutes(result_df3['装货时间'])>720)].sort_values('发车时间').reset_index(drop=True)
    result_df3['目的地'] = np.where(result_df3['司机所属地区'] == '长沙','创元','晟通')
    result_df3['始发地'] = np.where(result_df3['司机所属地区'] == '常德','创元','晟通')
    result_df3.insert(0, '序', [f'第{i+len(result_df1)+len(result_df2)}车' for i in range(len(result_df3))])
    result_df3.loc[len(result_df3)] = [' '] * len(result_df3.columns)

    result_df4 = time_plan_df[time_plan_df['货物类型'] == '双零箔'].copy()
    result_df4.loc[:, '发车时间'] = [' ']
    result_df4.loc[:, '始发地'] = '晟通'
    result_df4.loc[:, '目的地'] = ' '
    result_df4.insert(0, '序', [f'第{i+len(result_df1)+len(result_df2)+len(result_df3)-1}车' for i in range(len(result_df4))])

    result_df = pd.concat([result_df1, result_df2, result_df3, result_df4], axis=0, ignore_index=True)

    return result_df



# 出车时间计算函数（根据装货时间计算）
def calculate_work_start_time(
        *,
        load_time: str,  # 装货时间 "HH:MM"
        departure_time:str,
        region: str,  # "长沙" / "常德"
        cargo_type: str,  # "铝卷" / "铝棒" / "单顶" / "双零箔" / "废铝"
) -> str:
    """
        规则：
          - 常德：出车 = 装货
          - 长沙：
              * 废铝/双零箔：出车 = 装货
              * 其他（铝卷/铝棒/单顶）：出车 = 装货 - 3.5h
          - 若 废铝 且非甩挂 且 apply_non_drop_scrap_shift=True，则出车 +1h
        """
    dm = time_to_minutes(departure_time)
    if region == "常德":
        lm = time_to_minutes(load_time)
        dep_min = lm
    elif region == "长沙":
        if cargo_type in ("废铝/铝卷"):
            dep_min = dm
        elif cargo_type in ( "双零箔"):
            lm = time_to_minutes(load_time)
            dep_min = lm
        else:
            lm = time_to_minutes(load_time)
            dep_min = lm - int(3.5 * 60)
    else:
        raise ValueError("region 只能是 '长沙' 或 '常德'")
    return minutes_to_time(dep_min)
# 这里计算的数据来源当天排好的数据
# 计算到货时间,单条记录
'''调用时这样写：
    for idx, row in df.iterrows():
        cargo = row["货物"]
        load_time = row["装货时间"]

        if cargo_type == "废铝/铝卷":
            # 找到该类货物的第一行 index
            first_idx = df.index[df["货物"]=="废铝/铝卷"][0]
            is_first = (idx == first_idx)
        else:
            is_first = False

        arrive_time = calculate_arrive_time(
            cargo_type=cargo,
            load_time=load_time,
            is_first_special=is_first
        )
'''
def calculate_arrive_time(
        *,
        cargo_type: str,
        dep_time: str,
        is_second_special: bool = False
) -> str:
    """
      规则：
        - 铝箔废铝/铝卷：第1趟 +9.5h，第2趟(及以后) +10.5h
        - 其他货物：+3.5h
      """
    if cargo_type == "废铝/铝卷":
        if is_second_special == True:  # 判断是不是第一行
            # 第2趟 +10.5h
            arr_min = time_to_minutes(dep_time) + 10.5 * 60
        else:
            # 其他 +9.5h
            arr_min = time_to_minutes(dep_time) + 9.5 * 60
    else:
        arr_min = time_to_minutes(dep_time) + 3.5 * 60
    arrive_time = minutes_to_time(int(arr_min))
    return arrive_time

# 判断区间是否在午饭时间(12:00-13:00)或晚饭时间(17:00-18:00)（这个写错了，是区间）
def overlaps_lunch_or_dinner(arrive_time: str,cargo_type: str) -> bool:
    '''
    -判断卸货时间是否在吃饭区间内
      - 铝卷：+30min
      - 铝棒：+60min
      - 单顶：+120min
    '''
    L0, L1, L3, L4 = 12 * 60 + 1, 13 * 60- 1 , 17 * 60+ 1 , 18 * 60 - 1
    delta = 0
    arrive_min =time_to_minutes(arrive_time)
    if cargo_type in ['铝卷','废铝/铝卷']:
        delta = 30
    elif cargo_type == "铝棒":
        delta = 60
    elif cargo_type == "单顶":
        delta = 120
    else:
        delta = 0
    ult_min = arrive_min + delta
    # 区间重叠判断函数（半开区间 [a_start, a_end)）,b是吃饭时间段
    def overlaps(a_start, a_end, b_start, b_end):
        if a_end < b_start or b_end < a_start:
            return False
        else:
            return True
    # 判断区间是否与午饭时间(12:00-13:00)或晚饭时间(17:00-18:00)相撞
    if overlaps(arrive_min,ult_min,L0,L1) or overlaps(arrive_min,ult_min,L3,L4):
        return True
    else:
        return False

# 卸货完成时间
def calculate_unload_done_time(
        *,
        arrive_time: str,
        cargo_type: str,
        load_time: str
):
    '''
        -第一车铝卷，到货时间+1h;
        -铝卷+0.5,铝棒+1h,单顶+2h;
        -是否吃饭时间+1h;
    '''
    arr_min = time_to_minutes(arrive_time)
    if cargo_type in ["铝卷","废铝/铝卷","铝卷（甩废铝）","铝卷（废铝）"]:
        if load_time == "5:30":  # 判断是不是第一行
            # 第1趟 +1h
            uld_min = arr_min + 1 * 60
        else:
            # 第2趟及以后 +0.5h
            uld_min = arr_min + 0.5 * 60
    elif cargo_type == "铝棒":
        uld_min = arr_min + 1 * 60
    elif cargo_type == "单顶":
        uld_min = arr_min + 3 * 60

    if overlaps_lunch_or_dinner(arrive_time, cargo_type):
        uld_min += 60
    unload_done_time = minutes_to_time(int(uld_min))
    return unload_done_time


# 计算收车时间
def calculate_work_end_time(
        *,
        cargo_type: str,  # 货物
        unload_done_time: str,  # 卸货完成时间 "HH:MM"
        region: str,  # "长沙" / "常德"
        is_transfer: str,  # 是否接车
        load_time: str  # 常德：接车且第一趟 +0.5h
) -> str:
    """
        规则：
        双零箔：20:00
        其他：
          - 长沙：非接车 +0.5h；接车 +0
          - 常德：非接车 +4h；接车 +3.5h；接车且第一趟再 +0.5h
        """
    ud = time_to_minutes(unload_done_time)
    if cargo_type == "双零箔":
        off_min = 20 * 60
    else:
        if region == "长沙":
            if is_transfer == "是":
                off_min = ud + 0
            else:
                off_min = ud + 30
        elif region == "常德":
            if is_transfer == "是":
                off_min = ud + 3.5 * 60 + (30 if load_time == "5:30" else 0)
            else:
                off_min = ud + 4 * 60
        else:
            raise ValueError("region 只能是 '长沙' 或 '常德'")
    return minutes_to_time(int(off_min))

# 按照双零箔运输次数进行特殊排序
def double_zero_priority_sort(row):
    double_zero_count = row.get('month_double_zero_count', 0)
    # 4天1循环
    if double_zero_count in [1, 2, 3]:
        return 1
    elif double_zero_count == 0:
        return 2
    elif double_zero_count == 4:
        return 4
    else:  # 3次
        return 3


